package com.treeroot.treenet.protocol.tcp;

import com.treeroot.treenet.common.tools.CheckTools;
import com.treeroot.treenet.enums.ProtocolTypeMenu;
import com.treeroot.treenet.protocol.ConnectDataCallback;
import com.treeroot.treenet.protocol.abs.tcp.AbsTcpConnection;
import com.treeroot.treenet.protocol.abs.tcp.decode.DecodedMessage;
import com.treeroot.treenet.protocol.abs.tcp.decode.DefaultMessageDecoder;
import com.treeroot.treenet.protocol.abs.tcp.decode.FrameDecoder;
import com.treeroot.treenet.protocol.abs.tcp.session.TcpSession;
import com.treeroot.treenet.protocol.abs.tcp.session.WriteBufferQueue;
import com.treeroot.treenet.strategy.ProtocolStrategyHandle;
import lombok.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.List;

/**
 * Description: 处理tcp协议
 * Create By TreeRoot
 * Create Time: 2025/06/02 02:01
 * Class Name: HandleTcpProtocol
 *
 * @author TreeRoot
 */
public class TcpConnection extends AbsTcpConnection implements ProtocolStrategyHandle {

    private static final Logger log = LoggerFactory.getLogger(TcpConnection.class);

    @Override
    public void handleRequest(@NonNull ProtocolTypeMenu protocolType) {
        log.info("开始处理 TCP 协议类型: {}", protocolType);
        // 传入连接事件处理器
        this.handleRequest(this::acceptConnection);
    }

    @Override
    public void acceptConnection(@NonNull TcpSession tcpSession) {
        ServerSocketChannel serverChannel = tcpSession.getServerSocketChannel();
        try {
            SocketChannel clientChannel = serverChannel.accept();
            if (CheckTools.isNullOrEmpty(clientChannel)) {
                log.warn("接受客户端连接失败");
                return;
            }
            tcpSession.setClientChannel(clientChannel);
            tcpSession.setAcceptIp(clientChannel.getRemoteAddress().toString());
            tcpSession.setChannelId(tcpSession.createChannelId());
            tcpSession.setWriteBufferQueue(new WriteBufferQueue(clientChannel));
            log.info("【===================通道{}开始接收新的连接请求===================】", tcpSession.getChannelId());
        } catch (IOException e) {
            log.error("接受客户端连接失败", e);
        }
    }


    @Override
    public void readDataFromClient(@NonNull SelectionKey key, ConnectDataCallback connectDataCallback) {
        SocketChannel clientChannel = (SocketChannel) key.channel();
        TcpSession session = (TcpSession) key.attachment();
        FrameDecoder frameDecoder = session.getFrameDecoder();
        // 8KB 缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
        try {
            int bytesRead = clientChannel.read(buffer);
            if (bytesRead == -1) {
                log.info("客户端关闭连接: {}", clientChannel.getRemoteAddress());
                key.cancel();
                clientChannel.close();
                connectDataCallback.customerClosed();
                return;
            }
            // 准备读取数据
            buffer.flip();
            List<DecodedMessage> messageList;
            try {
                messageList = frameDecoder.decode(buffer);
                log.info("收到有效数据 开始处理===>>");
            } catch (IllegalArgumentException e) {
                log.warn("解码异常，丢弃buffer数据并关闭连接", e);
                key.cancel();
                clientChannel.close();
                return;
            }
            for (DecodedMessage message : messageList) {
                session.getRouter().route(message, session);
            }
        } catch (IOException e) {
            log.error("读取客户端数据异常", e);
            try {
                clientChannel.close();
            } catch (IOException ex) {
                log.error("关闭客户端连接失败", ex);
            }
            key.cancel();
        }
    }

    @Override
    public void acceptBefore(TcpSession tcpSession) {
        log.info("准备接受新客户端连接...");

        try {
            // 限制连接数（示例阈值）
            int maxConnections = 1000;
            int currentConnections = tcpSession.getSelector().keys().size();
            if (currentConnections >= maxConnections) {
                log.warn("当前连接数 {} 已达到上限 {}，拒绝新连接", currentConnections, maxConnections);
                throw new IllegalStateException("连接数超过最大限制");
            }

            //  IP 白名单或黑名单校验

        } catch (Exception e) {
            log.error("acceptBefore 连接前校验失败: ", e);
            throw new RuntimeException("拒绝新连接", e);
        }
    }

    @Override
    public void acceptAfter(TcpSession tcpSession) throws IOException {
        SocketChannel clientChannel = tcpSession.getClientChannel();
        Selector selector = tcpSession.getSelector();
        clientChannel.configureBlocking(false);
        SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ);
        // 创建并注入独立 FrameDecoder
        FrameDecoder frameDecoder = new FrameDecoder(new DefaultMessageDecoder());
        tcpSession.setFrameDecoder(frameDecoder);
        clientKey.attach(tcpSession);
        log.info("客户端连接已注册到选择器通道id: {}", tcpSession.getChannelId());

    }
}